package graphique;

/*
 * Lesson05.java
 *
 * Created on July 15, 2003, 11:30 AM
 */

import general.Case;
import general.Mechanisme;
import geometry.Zone;

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.imageio.ImageIO;
import javax.media.opengl.*;
import javax.media.opengl.glu.GLU;
import javax.media.opengl.glu.GLUquadric;

import systems.Arbre;
import systems.L_System;

import com.sun.opengl.util.Animator;
import com.sun.opengl.util.texture.Texture;
import com.sun.opengl.util.texture.TextureIO;

/** Port of the NeHe OpenGL Tutorial (Lesson 5)
 * to Java using the Jogl interface to OpenGL.  Jogl can be obtained
 * at http://jogl.dev.java.net/
 *
 * @author Kevin Duling (jattier@hotmail.com)
 */


class Afficheur3D implements GLEventListener, KeyListener, MouseMotionListener, MouseWheelListener
{
	static Animator animator = null;

	private float rquad = 0.0f;
	private float rtri = 0.0f;

	int QUADS = 1;
	int TRIANGLES = 2;
	int TERRAIN = 3;
	int SIPHERE = 4;
	
	int HALO = 5;
	int OCEAN = 6;
	
	int POINT = 8;
	
	int ATMO = 9;
	
	int VEGE = 10;
	
	int ARBRE = 11;
	int ARBRE_MORT = 12;
	
	private double angleX = 0;
	private double angleY = 45;

	int posMX;
	int posMY;
	
	double zoom = 10;

	private double	difAngleX = 0;

	private double	difAngleY = 0;
	
	double angleL = 0;
	
	GLU glu=new GLU();
	
	int timer = 0;

	private Mechanisme	m;

	public Afficheur3D(Mechanisme m )
	{
		this.m = m;
	}

	/** Called by the drawable to initiate OpenGL rendering by the client.
	 * After all GLEventListeners have been notified of a display event, the 
	 * drawable will swap its buffers if necessary.
	 * @param gLDrawable The GLDrawable object.
	 */    
	public void display(GLAutoDrawable gLDrawable)
	{
		final GL gl = gLDrawable.getGL();
		

		
		if( timer % 30 == 0 )
		{
			m.avancement();
			//System.out.println( m.fs.WC.size() );
		}
		
		timer++;

		
		gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
		gl.glEnable(GL.GL_DEPTH_TEST);							// Enables Depth Testing
		gl.glDepthFunc(GL.GL_LEQUAL);								// The Type Of Depth Testing To Do
		gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);	// Really Nice Perspective Calculations
		
		gl.glMatrixMode(GL.GL_PROJECTION);
		gl.glLoadIdentity();
		
		GLU glu=new GLU();

		glu.gluPerspective(45.0f, 1, 0.1 , 200.0);
		glu.gluLookAt( 0f, 0f, -zoom , 0, 0 , 0, 0, 1, 0);

		gl.glMatrixMode(GL.GL_MODELVIEW);
		gl.glLoadIdentity();
		
		angleX += difAngleX;
		angleY += difAngleY;
		
		difAngleX *= 0.99;
		difAngleY *= 0.99;

		GLUquadric quadric=glu.gluNewQuadric();
		glu.gluQuadricNormals(quadric, GL.GL_TRUE);
		//glu.gluQuadricDrawStyle(quadric, GLU.GLU_LINE );
		gl.glLoadIdentity();

		gl.glCallList(HALO);

		// LUNE
		gl.glRotated( angleY , 1 , 0 , 0 );
		gl.glRotated( angleX , 0 , 0 , 1 );

		gl.glColor3f(0.0f,1,0.0f);
		glu.gluSphere(quadric, 1f, 32, 16);
		
		gl.glRotated( 90 , 0 , 1 , 0 );
		gl.glColor3f(1.0f,0,0.0f);
		gl.glRotated( -90 , 0 , 1 , 0 );

		if( m.miseAJourTerrain )
		{
			gl.glNewList( SIPHERE , GL.GL_COMPILE );
			constructionTerrainDynamique(gl);
			gl.glEndList();
			
			m.miseAJourTerrain = false;
		}
		
		//constructionTerrainDynamiqueAlea(gl);
		gl.glCallList(SIPHERE);
		
		//gl.glCallList(VEGE);
		afficherVEGE_Dynamique( gl );
		
		afficherEAU_Dynamique( gl );
		
		afficherCOULEUR_Dynamique( gl );


		
		gl.glCallList(ATMO);
		
		
		gl.glPushMatrix();
		gl.glRotated( angleL , 0 , 0 , 1 );
		
		gl.glPushMatrix();
		gl.glTranslatef( 0f, -0.0001f, 0f);
		gl.glCallList(OCEAN);
		gl.glPopMatrix();
		gl.glEnable(GL.GL_TEXTURE_2D);
		gl.glTranslatef( 0f, -3f, 0f);
		angleL += 0.5;

		gl.glColor4f(1f,1f,1f, 1f);
		texLune.bind();
		glu.gluQuadricTexture( quadric , true);
		glu.gluSphere(quadric, 0.3f, 32, 16);
		gl.glPopMatrix();
		
		
		gl.glDisable(GL.GL_TEXTURE_2D);
		
		gl.glPushMatrix();
		gl.glTranslatef( 0f, 1.3f, 0f);
		gl.glColor4f(1f,1f,1f, 1f);
		glu.gluSphere(quadric, 0.1f, 32, 16);
		gl.glPopMatrix();
		
		gl.glPushMatrix();
		gl.glRotated( 90 , 0 , 0 , 1 );
		gl.glTranslatef( 0f, 1.3f, 0f);
		gl.glColor4f(1f,0f,1f, 1f);
		glu.gluSphere(quadric, 0.1f, 32, 16);
		gl.glPopMatrix();
		
		gl.glPushMatrix();
		gl.glRotated( 90 , 1 , 0 , 0 );
		gl.glTranslatef( 0f, 1.3f, 0f);
		gl.glColor4f(0f,1f,1f, 1f);
		glu.gluSphere(quadric, 0.1f, 32, 16);
		gl.glPopMatrix();

		gl.glFlush();
		
		rtri += 1f;
		rquad += 0.15f;
	}

	private void constructionTerrainDynamiqueAlea(GL gl)
	{
		double modifR;
		
		int type = GL.GL_QUADS;
		double coef = 0.01;
		
		for( int i = 0 ; i < m.pl.carte.get(0).size() ; i++ )
		{
			Zone z = m.pl.carte.get(0).get(i);

			gl.glBegin( type );

			modifR = z.p1.alt * C.coefR + 1 + Math.random() * coef;
			color( gl , z.p1.alt , (float) (Math.abs( z.p1.sz ) / C.rayon) );
			gl.glVertex3d( z.p1.sx * modifR , z.p1.sy * modifR  , z.p1.sz * modifR );

			modifR = z.p2.alt * C.coefR + 1 + Math.random() * coef;
			color( gl , z.p2.alt, (float) (Math.abs( z.p2.sz ) / C.rayon) );
			gl.glVertex3d( z.p2.sx * modifR , z.p2.sy * modifR  , z.p2.sz * modifR  );

			modifR = z.p3.alt * C.coefR + 1 + Math.random() * coef;
			color( gl , z.p3.alt, (float) (Math.abs( z.p3.sz ) / C.rayon) );
			gl.glVertex3d( z.p3.sx * modifR , z.p3.sy * modifR  , z.p3.sz * modifR  );

			modifR = z.p4.alt * C.coefR + 1 + Math.random() * coef;
			color( gl , z.p4.alt, (float) (Math.abs( z.p4.sz ) / C.rayon) );
			gl.glVertex3d( z.p4.sx * modifR , z.p4.sy * modifR  , z.p4.sz * modifR  );
			
			gl.glEnd();
		}
	}

	private void afficherCOULEUR_Dynamique(GL gl)
	{
		double modifR;
		
		int type = GL.GL_QUADS;
		
		for( int i = 0 ; i < m.colorCases.size() ; i++ )
		{
			Zone z = m.colorCases.get(i).zone;
			
			gl.glColor3d( 0.1 , 0.1 , 0.1 );
			gl.glBegin( type );

			modifR = z.p1.alt * C.coefR + 1;
			gl.glVertex3d( z.p1.sx * modifR , z.p1.sy * modifR  , z.p1.sz * modifR );

			modifR = z.p2.alt * C.coefR + 1;
			gl.glVertex3d( z.p2.sx * modifR , z.p2.sy * modifR  , z.p2.sz * modifR  );

			modifR = z.p3.alt * C.coefR + 1;
			gl.glVertex3d( z.p3.sx * modifR , z.p3.sy * modifR  , z.p3.sz * modifR  );

			modifR = z.p4.alt * C.coefR + 1;
			gl.glVertex3d( z.p4.sx * modifR , z.p4.sy * modifR  , z.p4.sz * modifR  );
			
			gl.glEnd();
		}
	}

	private void afficherEAU_Dynamique(GL gl)
	{
		for( int i = 0 ; i < m.fs.waterCases.size() ; i++ )
		{
			Case c = m.fs.waterCases.get(i);

			double modifR = (c.zone.p1.alt ) * C.coefR + 1;
			double eau = c.eau * 100000 + 1;
			
			gl.glPushMatrix();
			
			gl.glTranslated( c.zone.p1.sx * modifR, c.zone.p1.sy * modifR, c.zone.p1.sz * modifR );
			
			
			//gl.glColor3d(0.5 + Math.log( eau ) * 0.2 , 0.3 , 0);
			
			if( c.type == 1)
			{
				gl.glColor3d(0.5 + Math.log( eau ) * 0.1 , 0, 0);
				
				if( c.source != null )
				{
					gl.glPushMatrix();
					
					gl.glRotated( -90 , 1, 0, 0 );

					gl.glRotated( 90 - c.source.angleTheta / (Math.PI * 2) * 360 , 0, 1 , 0 );
					gl.glRotated( 90 - c.source.anglePhi / (Math.PI * 2) * 360 , 1, 0, 0 );
					
					gl.glScaled( 2, 2, 2);
					gl.glCallList( (int) (listFumee + Math.random() * C.nFumee) );
					gl.glPopMatrix();
				}
				
				/*if( c.zone.p1.alt < C.borneWater )
				{
					gl.glCallList( (int) (listVapeur + Math.random() * C.nVapeur) );
				}*/
			}
			else if( c.type == 2 )
			{
				gl.glColor3d(0 , 0 , 1 - (0.1 + Math.log( eau ) * 0.1) );
			}
			
			gl.glScaled( 4, 4, 4);
			gl.glCallList(POINT);
			gl.glPopMatrix();
		}
	}

	private void afficherVEGE_Dynamique(GL gl)
	{
		double modifR;
		
		for( int i = 0 ; i < m.ps.aa.size() ; i++ )
		{
			gl.glPushMatrix();
			Arbre a = m.ps.aa.get(i);
			modifR = (a.moyAlt ) * C.coefR + 1;
			
			gl.glTranslated(a.moy.sx * modifR, a.moy.sy * modifR, a.moy.sz * modifR );

			gl.glRotated( -90 , 1, 0, 0 );

			gl.glRotated( 90 - a.angleTheta / (Math.PI * 2) * 360 , 0, 1 , 0 );
			gl.glRotated( 90 - a.anglePhi / (Math.PI * 2) * 360 , 1, 0, 0 );

			if( a.mode == 0 )
			{
				int mod = a.age / 10;
	
				if( a.age < 0 )
				{
					if( a.age < C.arbreAgeGraine )
					{
						gl.glCallList( ARBRE_MORT );
					}
				}
				else
					gl.glCallList( listA[mod] + a.type );
			}
			else if( a.mode == 1 )
			{
				if( a.age < C.arbreAgeFeuTron )
				{
					gl.glCallList( (int) (listFeu + Math.random() * C.nFeu) );
					gl.glCallList( (int) (listFumee + Math.random() * C.nFumee) );
				}
				else
				{
					gl.glCallList( ARBRE_MORT );
				}
			}

			gl.glPopMatrix();
		}
	}

	double baseR = 1;

	double total;

	double modifRelief = 1;

	double modifTetha = 0.25;
	double modifPhi   = 0.25;

	double startTetha1 = Math.PI/2 + Math.PI/4;
	double startPhi1 = -Math.PI/4;//Math.PI;
	
	double startTetha2 = Math.PI/2+ Math.PI/4;
	double startPhi2 = -Math.PI/4;//Math.PI;

	
	double totalSI = 32;
	
	double rayMoy = 1;
	
	private Texture	texLune;

	private int[]	listA;

	private int	listFeu;

	private int	listFumee;

	private int	listVapeur;
	
	private void constructionDisplayList( GL gl )
	{
		
		gl.glNewList( SIPHERE , GL.GL_COMPILE );
		constructionTerrainDynamique(gl);
		gl.glEndList();
		
		double modifR;
        
		/*
		gl.glNewList( ATMO , GL.GL_COMPILE );

		type = GL.GL_QUADS;
		
		gl.glColor3f( (float)0.8, (float)0.8, (float)0.8);
		
		for( int i = 0 ; i < m.as.lNuage.size() ; i++ )
		{
			modifR = m.as.lNuage.get(i).alt * C.coefR + 0.9;
			for( int j  = 0 ; j < m.as.lNuage.get(i).a.size() ; j++ )
			{
				Zone z = m.as.lNuage.get(i).a.get(j);
				
				colorN( gl , z.p1.alt );
				
				gl.glPushMatrix();
				
				gl.glTranslated( z.p1.sx * modifR , z.p1.sy * modifR  , z.p1.sz * modifR );
				
				double v = z.p1.alt * 17 +1;
				gl.glScaled(2, v, v);
				
				gl.glCallList(POINT);
				gl.glPopMatrix();
				
			}
		}
		
		gl.glEndList();
		*/
		
		
		gl.glNewList( HALO , GL.GL_COMPILE );
		
		double x1,x2,x3,x4,y1,y2,y3,y4;
		double rayonMin = 0.9;
		double rayonMax = 1 + 2 * C.coefR;
		
		for( double i = 0 ; i < 100 ; i++ )
		{
				gl.glBegin( GL.GL_QUADS );
				
				x1 = rayonMin * Math.cos( i/100 * Math.PI * 2 );
				x2 = rayonMax * Math.cos( i/100 * Math.PI * 2 );
				x3 = rayonMax * Math.cos( (i+1)/100 * Math.PI * 2 );
				x4 = rayonMin * Math.cos( (i+1)/100 * Math.PI * 2 );
				
				y1 = rayonMin * Math.sin( i/100 * Math.PI * 2 );
				y2 = rayonMax * Math.sin( i/100 * Math.PI * 2 );
				y3 = rayonMax * Math.sin( (i+1)/100 * Math.PI * 2 );
				y4 = rayonMin * Math.sin( (i+1)/100 * Math.PI * 2 );
				
				gl.glColor4f( 1.0f,1.0f,1.0f , 0.5f );
				gl.glVertex3d( x1 , y1  , 0  );
				
				gl.glColor4f( 0.0f,0.0f,0.0f , 0.5f );
				gl.glVertex3d( x2 , y2  , 0  );
				gl.glVertex3d( x3 , y3  , 0  );
				
				gl.glColor4f( 1.0f,1.0f,1.0f , 0.5f );
				gl.glVertex3d( x4 , y4  , 0  );
				
				gl.glEnd();
		}
		
		gl.glEndList();

		gl.glNewList( OCEAN , GL.GL_COMPILE );
		
		gl.glColor4f(0.2f, 0.2f,1f, 0.7f);
		GLUquadric quadric=glu.gluNewQuadric();
		glu.gluQuadricNormals(quadric, GL.GL_TRUE);
		modifR = C.borneWater * C.coefR + 1;
		glu.gluSphere(quadric, modifR , 32, 16);
		
		gl.glEndList();
		
		gl.glNewList( POINT , GL.GL_COMPILE );
		quadric=glu.gluNewQuadric();
		glu.gluQuadricNormals(quadric, GL.GL_TRUE);
		glu.gluSphere(quadric, 0.005 , 32, 16);
		gl.glEndList();
		
		gl.glNewList( ARBRE , GL.GL_COMPILE );
		quadric=glu.gluNewQuadric();
		glu.gluQuadricNormals(quadric, GL.GL_TRUE);
		glu.gluCylinder(quadric , 0.005 , 0.005 , 0.5 , 16, 16);
		gl.glEndList();
		
		gl.glNewList( 20 , GL.GL_COMPILE );
		quadric=glu.gluNewQuadric();
		glu.gluQuadricNormals(quadric, GL.GL_TRUE);
		glu.gluCylinder(quadric , 0.003 , 0.003 , 0.03 , 16, 16);
		gl.glEndList();
		
		gl.glNewList( ARBRE_MORT , GL.GL_COMPILE );
		gl.glColor3f( 0.4f , 0.2f , 0f );
		quadric=glu.gluNewQuadric();
		glu.gluQuadricNormals(quadric, GL.GL_TRUE);
		glu.gluCylinder(quadric , 0.002 , 0.002 , 0.04 , 16, 16);
		gl.glEndList();

		listA = new int[C.nNivArbre ];
		
		for( int i = 0 ; i < C.nNivArbre ; i++ )
		{
			listA[i] = gl.glGenLists( C.nDifArbre );
		}

		System.out.println("Commence a " + listA[0] );
		
		L_System ls = new L_System();
		
		for( int j = 0 ; j < C.nDifArbre ; j++ )
		{
			int rot = (int) (Math.random() * 180);
			
			for( int i = 0 ; i < C.nNivArbre ; i++ )
			{
				gl.glNewList( listA[i] + j , GL.GL_COMPILE);
				gl.glPushMatrix();
				gl.glRotated( rot , 0, 0, 1);
				gl.glScaled(0.5, 0.5, 0.5);
				String s = ls.developpment("A", i+1 );
				ls.construction(gl, s);
				gl.glPopMatrix();
				gl.glEndList();
			}
		}
		

		
		gl.glNewList( VEGE , GL.GL_COMPILE );
		
		afficherVEGE_Dynamique( gl);
		
		gl.glEndList();
		
		
		listFeu = gl.glGenLists( C.nFeu );
		listFumee = gl.glGenLists( C.nFumee );
		listVapeur = gl.glGenLists( C.nVapeur );
		
		for( int i = 0 ; i < C.nFeu ; i++ )
		{
			gl.glNewList( listFeu + i , GL.GL_COMPILE);
			Particule.feu(gl);
			gl.glEndList();
		}
		
		for( int i = 0 ; i < C.nFumee ; i++ )
		{
			gl.glNewList( listFumee + i , GL.GL_COMPILE);
			Particule.fumee(gl);
			gl.glEndList();
		}
		
		for( int i = 0 ; i < C.nVapeur ; i++ )
		{
			gl.glNewList( listVapeur + i , GL.GL_COMPILE);
			Particule.vapeur(gl);
			gl.glEndList();
		}
	}
	
	private void constructionTerrainDynamique(GL gl)
	{
		double modifR;
		
		int type = GL.GL_QUADS;

		for( int i = 0 ; i < m.pl.carte.get(0).size() ; i++ )
		{
			Zone z = m.pl.carte.get(0).get(i);

			gl.glBegin( type );

			modifR = z.p1.alt * C.coefR + 1;
			color( gl , z.p1.alt , (float) (Math.abs( z.p1.sz ) / C.rayon) );
			gl.glVertex3d( z.p1.sx * modifR , z.p1.sy * modifR  , z.p1.sz * modifR );

			modifR = z.p2.alt * C.coefR + 1;
			color( gl , z.p2.alt, (float) (Math.abs( z.p2.sz ) / C.rayon) );
			gl.glVertex3d( z.p2.sx * modifR , z.p2.sy * modifR  , z.p2.sz * modifR  );

			modifR = z.p3.alt * C.coefR + 1;
			color( gl , z.p3.alt, (float) (Math.abs( z.p3.sz ) / C.rayon) );
			gl.glVertex3d( z.p3.sx * modifR , z.p3.sy * modifR  , z.p3.sz * modifR  );

			modifR = z.p4.alt * C.coefR + 1;
			color( gl , z.p4.alt, (float) (Math.abs( z.p4.sz ) / C.rayon) );
			gl.glVertex3d( z.p4.sx * modifR , z.p4.sy * modifR  , z.p4.sz * modifR  );
			
			gl.glEnd();
		}

	}

	private void colorN(GL gl, float alt)
	{
		float v = 1-(float) ((alt-C.seuilT)/(1-C.seuilT));
		
		if( alt > C.seuilT )
		{
			gl.glColor4f( v , v, v , 1 );
		}
		else
		{
			gl.glColor4f(0, 0, 0, 0);
		}
	}

	private void color(GL gl , float alt , float lat )
	{
		float deltaH = (float) ((Math.random()-0.5) * 0.1);
		
		
		float colorLat = deltaH;
		if( lat > C.borneWinter && lat < C.borneArtic )
			colorLat += (lat-C.borneWinter)/(C.borneArtic-C.borneWinter);
		
		
		if( alt < C.borneBeach )
		{
			gl.glColor3f( (float) ((alt)/(C.borneBeach)) + colorLat , (float) ((alt)/(C.borneBeach)) + colorLat , colorLat );
		}
		else if( alt < C.borneMontain )
		{
			gl.glColor3f( colorLat , 1-(float) ((alt-C.borneWater)/(C.borneMontain-C.borneWater)) + colorLat , colorLat );
		}
		else
		{
			gl.glColor3f( (float) ((alt-C.borneMontain)/(1-C.borneMontain)) + colorLat , (float) ((alt-C.borneMontain)/(1-C.borneMontain)) + colorLat , (float) ((alt-C.borneMontain)/(1-C.borneMontain)) + colorLat);
		}
		
		if( lat > C.borneArtic )
			gl.glColor3f( 1 , 1 , 1 );
	}

	/** Called when the display mode has been changed.  <B>!! CURRENTLY UNIMPLEMENTED IN JOGL !!</B>
	 * @param gLDrawable The GLDrawable object.
	 * @param modeChanged Indicates if the video mode has changed.
	 * @param deviceChanged Indicates if the video device has changed.
	 */
	public void displayChanged(GLAutoDrawable gLDrawable, boolean modeChanged, boolean deviceChanged)
	{
	}

	/** Called by the drawable immediately after the OpenGL context is 
	 * initialized for the first time. Can be used to perform one-time OpenGL 
	 * initialization such as setup of lights and display lists.
	 * @param gLDrawable The GLDrawable object.
	 */
	public void init(GLAutoDrawable gLDrawable)
	{
		final GL gl = gLDrawable.getGL();
		gl.glShadeModel(GL.GL_SMOOTH);              // Enable Smooth Shading
		gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f);    // Black Background
		gl.glClearDepth(1.0f);                      // Depth Buffer Setup
		gl.glEnable(GL.GL_DEPTH_TEST);							// Enables Depth Testing
		gl.glEnable(GL.GL_DOUBLEBUFFER );
		gl.glDepthFunc(GL.GL_LEQUAL);								// The Type Of Depth Testing To Do
		gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);	// Really Nice Perspective Calculations
		
		gl.glEnable(GL.GL_BLEND);
		gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);

		gLDrawable.addKeyListener(this);
		gLDrawable.addMouseMotionListener(this);
		gLDrawable.addMouseWheelListener(this);
		
		gl.glEnable(GL.GL_TEXTURE_2D);
		BufferedImage im;
		
		try
		{
			im = ImageIO.read( new File("images/Lune.jpg") );
			texLune = TextureIO.newTexture( im , true );
		}
		catch(IOException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		
		constructionDisplayList( gl );
	}


	/** Called by the drawable during the first repaint after the component has 
	 * been resized. The client can update the viewport and view volume of the 
	 * window appropriately, for example by a call to 
	 * GL.glViewport(int, int, int, int); note that for convenience the component
	 * has already called GL.glViewport(int, int, int, int)(x, y, width, height)
	 * when this method is called, so the client may not have to do anything in
	 * this method.
	 * @param gLDrawable The GLDrawable object.
	 * @param x The X Coordinate of the viewport rectangle.
	 * @param y The Y coordinate of the viewport rectanble.
	 * @param width The new width of the window.
	 * @param height The new height of the window.
	 */
	public void reshape(GLAutoDrawable gLDrawable, int x, int y, int width, int height)
	{
		final GL gl = gLDrawable.getGL();
		final GLU glu = new GLU();

		if (height <= 0) // avoid a divide by zero error!
			height = 1;
		final float h = (float)width / (float)height;
		gl.glViewport(0, 0, width, height);
		gl.glMatrixMode(GL.GL_PROJECTION);
		gl.glLoadIdentity();
		glu.gluPerspective(45.0f, h, 0.0, 200.0);
		gl.glMatrixMode(GL.GL_MODELVIEW);
		gl.glLoadIdentity();
	}

	/** Invoked when a key has been pressed.
	 * See the class description for {@link KeyEvent} for a definition of
	 * a key pressed event.
	 * @param e The KeyEvent.
	 */
	public void keyPressed(KeyEvent e)
	{
		if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
		{
			animator.stop();
			System.exit(0);
		}
	}

	/** Invoked when a key has been released.
	 * See the class description for {@link KeyEvent} for a definition of
	 * a key released event.
	 * @param e The KeyEvent.
	 */
	public void keyReleased(KeyEvent e) {}

	/** Invoked when a key has been typed.
	 * See the class description for {@link KeyEvent} for a definition of
	 * a key typed event.
	 * @param e The KeyEvent.
	 */
	public void keyTyped(KeyEvent e) {}



	public void mouseDragged(MouseEvent arg0)
	{
		double modifAngle = 130;

		int difX = posMX - arg0.getX();
		int difY = posMY - arg0.getY();

		difAngleX = -(double)difX/C.taille * modifAngle;
		difAngleY = (double)difY/C.taille * modifAngle;

		posMX = arg0.getX();
		posMY = arg0.getY();

	}

	public void mouseMoved(MouseEvent arg0)
	{
		posMX = arg0.getX();
		posMY = arg0.getY();


		//arg0.
	}

	/** Program's main entry point
	 * @param args command line arguments.
	 */
	public static void main(String[] args)
	{
		Frame frame = new Frame("IA : World");
		GLCanvas canvas = new GLCanvas(new GLCapabilities());

		int puis = 6;
		
		int noise = puis-1;

		Mechanisme m = new Mechanisme( (int) Math.pow(2, puis) , noise );
		
		canvas.addGLEventListener(new Afficheur3D( m ));

		frame.add(canvas);
		frame.setSize(640, 640);
		animator = new Animator(canvas);
		frame.addWindowListener(new WindowAdapter()
		{
			public void windowClosing(WindowEvent e)
			{
				animator.stop();
				System.exit(0);
			}
		});
		frame.show();
		animator.start();
		canvas.requestFocus();
	}

	public void mouseWheelMoved(MouseWheelEvent arg0)
	{
		if( arg0.getWheelRotation() > 0 )
		{
			zoom = (zoom-1) * 0.9 + 1;
		}
		else
		{
			zoom = (zoom-1) * 1.1 + 1;
		}
		
		//System.out.println(zoom);
	}
}
